package com.blog.common.redis.service.impl;

import com.blog.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * spring redis 工具实现类
 * </p>
 *
 * @author Valerie
 * @date 2023/2/22
 **/
@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 删除单个key
     *
     * @param key 键
     * @return Boolean
     */
    @Override
    public Boolean del(final String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 删除多个key
     *
     * @param keys 键
     * @return Long
     */
    @Override
    public Long del(final String... keys) {
        return redisTemplate.delete(Arrays.asList(keys));
    }

    @Override
    public Long del(Collection<String> keyList) {
        return redisTemplate.delete(keyList);
    }

    /**
     * 删除多个key
     *
     * @param key 键
     * @return Long
     */
    @Override
    public Set<String> keys(final String key) {
        return redisTemplate.opsForValue().getOperations().keys(key);
    }

    /**
     * 设置过期时间
     *
     * @param key     键
     * @param timeout 时间秒
     * @return Long
     */
    @Override
    public Boolean expire(final String key, final Long timeout) {
        return redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置过期时间
     *
     * @param key     键
     * @param timeout 时间
     * @param unit    时间单位
     * @return Long
     */
    @Override
    public Boolean expire(final String key, final Long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }


    /**
     * 设置过期时间
     *
     * @param key 键
     * @return Long
     */
    @Override
    public Boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }


    @Override
    public Long persist(final String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }


    @Override
    public Long persist(final String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /* for string*/

    @Override
    public Object get(final String key) {
        return redisTemplate.opsForValue().get(key);
    }


    @Override
    public <T> T get(String key, Class<T> clazz) {
        try {
            return clazz.cast(get(key));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public void set(final String key, final Object value) {
        redisTemplate.opsForValue().set(key, value);
    }


    @Override
    public void set(final String key, final Object value, final Long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }


    @Override
    public Long incr(final String key) {
        return redisTemplate.opsForValue().increment(key);
    }


    @Override
    public Long incr(final String key, final Long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }


    @Override
    public Double incr(final String key, final Double delta) {

        return redisTemplate.opsForValue().increment(key, delta);
    }


    @Override
    public Long strlen(final String key) {
        return redisTemplate.opsForValue().size(key);
    }

    /* for Hash */


    @Override
    public Object hGet(final String key, final Object hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    @Override
    public <T> T hGet(final String key, final Object hashKey, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForHash().get(key, hashKey));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }


    @Override
    public Map<Object, Object> hGetAll(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public <K, V> Map<K, V> hGetAll(String key, Class<K> keyClass, Class<V> valClass) {

        try {
            return redisTemplate.opsForHash().entries(key).entrySet().stream()
                    .collect(Collectors.toMap(entry -> keyClass.cast(entry.getKey()),
                            entry -> valClass.cast(entry.getValue())));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public void hPut(final String key, final Object hashKey, final Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    @Override
    public Double hIncr(final String key, final Object hashKey, final Double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    @Override
    public Long hIncr(final String key, final Object hashKey, final Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    @Override
    public Double hDecr(final String key, final Object hashKey, final Double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    @Override
    public Long hDecr(final String key, final Object hashKey, final Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    @Override
    public void hPutAll(final String key, final Map<?, ?> map) {
        redisTemplate.opsForHash()
                .putAll(key, map.entrySet()
                        .stream()
                        .collect(Collectors.toMap(k -> String.valueOf(k.getKey()), Map.Entry::getValue)));
    }


    @Override
    public Long hSize(final String key) {
        return redisTemplate.opsForHash().size(key);
    }


    @Override
    public Boolean hHasKey(final String key, final Object hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }


    @Override
    public List<Object> hGetValues(final String key) {
        return redisTemplate.opsForHash().values(key);
    }

    @Override
    public <T> List<T> hGetValues(String key, Class<T> clazz) {
        try {
            return redisTemplate.opsForHash().values(key).stream()
                    .map(clazz::cast)
                    .collect(Collectors.toList());
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public Set<Object> hGetKeys(final String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    @Override
    public <T> Set<T> hGetKeys(String key, Class<T> clazz) {
        try {
            return redisTemplate.opsForHash().values(key).stream()
                    .map(clazz::cast)
                    .collect(Collectors.toSet());
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    /* for set */


    @Override
    public Long sAdd(final String key, final Object val) {
        return redisTemplate.opsForSet().add(key, val);
    }


    @Override
    public Long sAdd(final String key, final Object... val) {
        return redisTemplate.opsForSet().add(key, val);
    }

    @Override
    public Long sRemove(final String key, final Object... val) {
        return redisTemplate.opsForSet().remove(key, val);
    }

    @Override
    public Long sSize(final String key) {
        return redisTemplate.opsForSet().size(key);
    }

    @Override
    public Boolean sIsMember(final String key, final Object val) {
        return redisTemplate.opsForSet().isMember(key, val);
    }

    @Override
    public Map<Object, Boolean> sIsMember(final String key, final Object... val) {
        return redisTemplate.opsForSet().isMember(key, val);
    }

    @Override
    public Set<Object> sMembers(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    @Override
    public <T> Set<T> sMembers(String key, Class<T> clazz) {
        try {
            return Objects.requireNonNull(redisTemplate.opsForSet().members(key)).stream()
                    .map(clazz::cast)
                    .collect(Collectors.toSet());
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public Boolean zAdd(final String key, final Object val, final Double score) {
        return redisTemplate.opsForZSet().add(key, val, score);
    }


    @Override
    public Boolean zAddIfAbsent(final String key, final Object val, Double score) {
        return redisTemplate.opsForZSet().addIfAbsent(key, val, score);
    }


    @Override
    public Long zAdd(final String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        return redisTemplate.opsForZSet().add(key, tuples);
    }


    @Override
    public Long zCard(final String key) {
        return redisTemplate.opsForZSet().size(key);
    }


    @Override
    public Double zScore(final String key, final Object val) {
        return redisTemplate.opsForZSet().score(key, val);
    }


    @Override
    public List<Double> zScore(final String key, final Object... val) {
        return redisTemplate.opsForZSet().score(key, val);
    }

    @Override
    public Map<Object, Double> zGetAll(final String key) {
        return Objects.requireNonNull(Objects.requireNonNull(redisTemplate.opsForZSet().rangeWithScores(key, 0, -1))
                .stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore)));
    }

    @Override
    public Long zRemove(final String key, final Object... val) {
        return redisTemplate.opsForZSet().remove(key, val);
    }


    @Override
    public Long zCount(final String key, final Double min, final Double max) {
        return redisTemplate.opsForZSet().count(key, min, max);
    }


    @Override
    public Double zIncrement(final String key, final Object val, final Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, val, score);
    }

    @Override
    public Double zDecrement(final String key, final Object val, final Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, val, -score);
    }

    /* for List */


    @Override
    public Long lPush(final String key, final Object val) {
        return redisTemplate.opsForList().leftPush(key, val);
    }


    @Override
    public Long lPush(final String key, final Object pivot, final Object val) {
        return redisTemplate.opsForList().leftPush(key, pivot, val);
    }


    @Override
    public Long lPushAll(final String key, final Object... val) {
        return redisTemplate.opsForList().leftPushAll(key, val);
    }


    @Override
    public Long lPushAll(final String key, final Collection<?> val) {
        return redisTemplate.opsForList().leftPushAll(key, val);
    }


    @Override
    public Object lPop(final String key) {
        return redisTemplate.opsForList().leftPop(key);
    }


    @Override
    public List<Object> lPop(final String key, final long count) {
        return redisTemplate.opsForList().leftPop(key, count);
    }


    @Override
    public Object blPop(final String key, final long timeout) {
        return redisTemplate.opsForList().leftPop(key, timeout, TimeUnit.SECONDS);
    }


    @Override
    public Object blPop(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.opsForList().leftPop(key, timeout, unit);
    }


    @Override
    public Long lastIndexOf(final String key, final Object val) {
        return redisTemplate.opsForList().lastIndexOf(key, val);
    }


    @Override
    public Long indexOf(final String key, final Object val) {
        return redisTemplate.opsForList().indexOf(key, val);
    }


    @Override
    public Long rPush(final String key, final Object val) {
        return redisTemplate.opsForList().leftPush(key, val);
    }

    @Override
    public Long rPush(final String key, final Object pivot, final Object val) {
        return redisTemplate.opsForList().leftPush(key, pivot, val);
    }


    @Override
    public Long rPushAll(final String key, final Object... val) {
        return redisTemplate.opsForList().leftPushAll(key, val);
    }


    @Override
    public Long rPushAll(final String key, final Collection<?> val) {
        return redisTemplate.opsForList().leftPushAll(key, val);
    }


    @Override
    public Object rPop(final String key) {
        return redisTemplate.opsForList().leftPop(key);
    }


    @Override
    public List<Object> rPop(final String key, final long count) {
        return redisTemplate.opsForList().rightPop(key, count);
    }

    @Override
    public Object brPop(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.opsForList().rightPop(key, timeout, unit);
    }

    @Override
    public <T> T lPop(String key, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForList().leftPop(key));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> List<T> lPop(String key, long count, Class<T> clazz) {
        try {
            return Objects.requireNonNull(redisTemplate.opsForList().leftPop(key, count))
                    .stream()
                    .map(clazz::cast)
                    .collect(Collectors.toList());
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> T blPop(String key, long timeout, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForList().leftPop(key, timeout));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> T blPop(String key, long timeout, TimeUnit unit, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForList().leftPop(key, timeout, unit));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> T rPop(String key, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForList().rightPop(key));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> List<T> rPop(String key, long count, Class<T> clazz) {
        try {
            return Objects.requireNonNull(redisTemplate.opsForList().rightPop(key, count))
                    .stream()
                    .map(clazz::cast)
                    .collect(Collectors.toList());
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }

    @Override
    public <T> T brPop(String key, long timeout, TimeUnit unit, Class<T> clazz) {
        try {
            return clazz.cast(redisTemplate.opsForList().rightPop(key, timeout, unit));
        }catch (ClassCastException e){
            log.error("类型转换失败 msg->{}", e.getMessage());
            return null;
        }
    }
}
